package com.chentf.creational.Singleton.code;

/**
 * 双重检锁
 * 双检锁，又叫双重校验锁，综合了懒汉式和饿汉式两者的优缺点整合而成。
 * 看上面代码实现中，特点是在synchronized关键字内外都加了一层 if 条件判断，
 * 这样既保证了线程安全，又比直接上锁提高了执行效率，还节省了内存空间。
 */
public class DoubleCheck {

    /**
     * volatile关键字的含义是：被其所修饰的变量的值不会被本地线程缓存，所有对该变量的读写都是直接操作共享内存来实现，
     * 从而确保多个线程能正确的处理该变量。该关键字可能会屏蔽掉虚拟机中的一些代码优化，所以其运行效率可能不是很高，
     * 所以，一般情况下，并不建议使用双重加锁机制，酌情使用才是正理！
     */
    private static volatile DoubleCheck instance = null;

    private DoubleCheck(){}

    /**
     * 双重指的的双重判断，而加锁单指那个synchronized，为什么要进行双重判断，其实很简单，
     * 第一重判断，如果单例已经存在，那么就不再需要进行同步操作，而是直接返回这个实例，如果没有创建，才会进入同步块，
     * 同步块的目的与之前相同，目的是为了防止有两个调用同时进行时，导致生成多个实例，
     * 有了同步块，每次只能有一个线程调用能访问同步块内容，当第一个抢到锁的调用获取了实例之后，这个实例就会被创建，
     * 之后的所有调用都不会进入同步块，直接在第一重判断就返回了单例。至于第二个判断，个人感觉有点查遗补漏的意味在内
     */
    public static DoubleCheck getInstance(){
        if(instance == null){
            synchronized (DoubleCheck.class){
                if(instance == null){
                    instance = new DoubleCheck();
                }
            }
        }
        return instance;
    }
}
